use std::fs;
use async_trait::async_trait;
use loco_rs::{
    app::{AppContext, Hooks, Initializer},
    bgworker::{BackgroundWorker, Queue},
    boot::{create_app, BootResult, StartMode},
    config::Config,
    controller::AppRoutes,
    db::{self, truncate_table},
    environment::Environment,
    task::Tasks,
    Result,
};

use axum::{
    response::Html,
    routing::get,
    Router,
};

use migration::Migrator;
use std::path::Path;
use loco_rs::prelude::IntoResponse;
use loco_openapi::prelude::{*};
#[allow(unused_imports)]
use crate::{controllers, models::_entities::users, tasks, workers::downloader::DownloadWorker};

pub struct App;
#[async_trait]
impl Hooks for App {
    fn app_name() -> &'static str {
        env!("CARGO_CRATE_NAME")
    }

    fn app_version() -> String {
        format!(
            "{} ({})",
            env!("CARGO_PKG_VERSION"),
            option_env!("BUILD_SHA")
                .or(option_env!("GITHUB_SHA"))
                .unwrap_or("dev")
        )
    }

    async fn boot(
        mode: StartMode,
        environment: &Environment,
        config: Config,
    ) -> Result<BootResult> {
        create_app::<Self, Migrator>(mode, environment, config).await
    }

    async fn initializers(_ctx: &AppContext) -> Result<Vec<Box<dyn Initializer>>> {
        Ok(vec![Box::new(
            loco_openapi::OpenapiInitializerWithSetup::new(
                |ctx| {
                    #[derive(OpenApi)]
                    #[openapi(
                        modifiers(&SecurityAddon),
                        info(
                            title = "maco 的loco框架实现版本",
                            description = "这个项目实现了maku的java项目的全部功能"
                        )
                    )]
                    struct ApiDoc;
                    set_jwt_location(ctx.into());

                    ApiDoc::openapi()
                },
                // When using automatic schema collection only
                None,
                // When using manual schema collection
                // Manual schema collection can also be used at the same time as automatic schema collection
                // Some(vec![controllers::album::api_routes()]),
            ),
        )])
    }

    fn routes(_ctx: &AppContext) -> AppRoutes {
        AppRoutes::with_default_routes() // controller routes below
            .add_route(controllers::auth::routes())
    }

    // async fn after_routes(router: axum::Router, ctx: &AppContext) -> Result<axum::Router> {
    //     // ⚠️ 关键：确保 loco-openapi 不注册 /scalar
    //     // 方法：不要在 config.yaml 中配置 scalar.url
    //
    //     // 创建自定义路由，提供本地 Scalar 页面
    //     let custom_router = axum::Router::new().route("/scalar", get(|| async {
    //         let base_dir = std::env::current_dir().expect("无法获取当前目录");
    //         let html_path = base_dir.join("public").join("scalar").join("index.html");
    //
    //         match fs::read_to_string(html_path) {
    //             Ok(html) => Html(html).into_response(),
    //             Err(e) => (
    //                 axum::http::StatusCode::NOT_FOUND,
    //                 format!("Scalar 文档未找到: {}", e),
    //             )
    //                 .into_response(),
    //         }
    //     }));
    //
    //     // 合并路由
    //     // 如果 loco-openapi 已经注册了 /scalar，则它会优先匹配（先注册）
    //     // 所以我们必须确保它没有注册
    //     Ok(router.merge(custom_router))
    //
    // }


    async fn connect_workers(ctx: &AppContext, queue: &Queue) -> Result<()> {
        queue.register(DownloadWorker::build(ctx)).await?;
        Ok(())
    }

    #[allow(unused_variables)]
    fn register_tasks(tasks: &mut Tasks) {
        // tasks-inject (do not remove)
    }
    async fn truncate(ctx: &AppContext) -> Result<()> {
        truncate_table(&ctx.db, users::Entity).await?;
        Ok(())
    }
    async fn seed(ctx: &AppContext, base: &Path) -> Result<()> {
        db::seed::<users::ActiveModel>(&ctx.db, &base.join("users.yaml").display().to_string())
            .await?;
        Ok(())
    }
}
